package com.qying.limit;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 固定窗口限流
 *
 *限流算法:
 *1.固定窗口限流算法
 *先维护一个计数器 count,将单位时间time作为一个窗口 1s,计数器记录窗口
 *接收请求的次数
 *当次数小于限流阈值,就允许访问,计数器 count+1
 *当次数大于限流阈值,就拒绝访问
 *当前时间窗口过去之后,计数器清零
 *eg:
 *假设单位时间是1秒，限流阀值为3。在单位时间1秒内，每来一个请求,计数器就加1，如果计数器累加的次数超过限流阀值3，后续的请求全部拒绝。等到1s结束后，计数器清0，重新开始计数
 */

/**
 * 算法缺点
 * 如果阈值为5,单位时间窗口为1s,如果再单位时间类 0.8-1s 和 1-1.2s 分别并发5个请求.虽然没有超过
 * 阈值,但是如果算 0.8-1.2s 的并发数高达10,已经超过单位时间1s不超过5阈值的规定
 */
public class FixLimit {

    //计数器
    private AtomicInteger counter;

    //阈值
    private final static int threshold = 3;

    //时间口单位 3s
    private final static int windowUnit = 1;

    //记录最后请求的时间
    private long lastRequestTime = 0l;

    public static void main(String[] args) {

        System.out.println("12345".length());

        FixLimit fixLimit = new FixLimit();


//        for (int i = 0; i< 100; i++) {
//            new Thread(new Runnable() {
//                @Override
//                public void run() {
//                    boolean b = fixLimit.fixedWindowsTryAcquire();
//                    if (b) {
//                        System.out.println("111111111111111");
//                    }else {
//                        System.out.println("222222222222222");
//                    }
//                }
//            }).start();
//        }

    }


    /**
     * 固定窗口时间算法
     * @return
     */
    boolean fixedWindowsTryAcquire() {

        long currentTime = System.currentTimeMillis();  //获取系统当前时间
        if (currentTime - lastRequestTime > windowUnit) {  //检查是否在时间窗口内
            counter = new AtomicInteger(0);  // 计数器清0
            lastRequestTime = currentTime;  //开启新的时间窗口
        }

        if (counter.get() < threshold) {  // 小于阀值
            counter.incrementAndGet();  //计数器加1
            return true;
        }

        return false;
    }
}
